package com.xbongbong.paas.util;

import com.alibaba.fastjson.JSONArray;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.ExcelConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.exception.ExcelAnalysisException;
import com.xbongbong.paas.exception.ExcelTitleCheckException;
import com.xbongbong.paas.help.ImportRedisHelper;
import com.xbongbong.paas.help.ImportSendHelper;
import com.xbongbong.paas.pojo.ErrorExcelDataPojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.ImportStatusPojo;
import com.xbongbong.paas.pojo.ReadExcelDataReturnPojo;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.ImportMessageFormDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.HandleImportService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.PackageStatusEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.ValueAddedTypeEnum;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.export.ImportConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.service.toolbox.help.PackageStatusHelp;
import org.apache.poi.ss.util.CellAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

/**
 * 用于处理07Excel的行数据内容处理
 * @author 魏荣杰
 * @date 2019/11/20 11:18 下午
 * @since v4.6.0
 * @version v4.6.0
 */
public class ExcelXlsxSheetContentsHandler implements XSSFSheetXMLHandler.SheetContentsHandler, ExcelXMLProcedure {
    private static final Logger LOG = LoggerFactory.getLogger(ExcelXlsxSheetContentsHandler.class);
    /**
     * 是否是一行的第一个单元格
     */
    private boolean firstCellOfRow = false;
    /**
     * 当前行
     */
    private int currentRowNumber = -1;
    /**
     * 当前列
     */
    private int currentColNumber = -1;
    /**
     * 开始读取行数从第0行开始计算, 控制Excel读取起初位置，-1为从第一行读取
     */
    private int rowIndex = 0;
    /**
     * 一行的数据
     */
    private List<String> rowCells = new ArrayList<>();
    /**
     * 读取的行数
     */
    private int totalRows = 0;
    /**
     * 标题
     */
    private List<List<String>> titleLists = new ArrayList<>();
    /**
     * 每次处理完一行数据后的分组数据集合，用于在最后文档读完时，将不满xx组数据的推到mq去处理
     */
    private ReadExcelDataReturnPojo readExcelDataReturnPojo;
    // 以下参数都需要从外部传入
    /**
     * 解释
     */
    private List<FieldAttrEntityForImport> fieldAttrEntityList;

    private ImportFormDataDTO importFormDataDTO;
    /**
     * 表格名称
     */
    private String sheetName;
    /**
     * 数据开始的行数
     */
    private int startRowIndex;
    /**
     * 表格索引值
     */
    private int sheetIndex;
    /**
     * 实际的总行数（去掉表头）
     */
    private int totalRowNum = 0;
    /**
     * 实际计算出来的总行数(可能存在获取的总行数信息不对，需要最准确的信息)
     */
    private int actualTotalRowNum = 0;
    /**
     * 是否是第一行数据
     */
    private boolean isFirstRow = true;

    /**
     * 粗略的分片大小
     */
    private int falseTotalFragmentation;

    private ExcelReadDataDelegated excelReadDataDelegated;

    private ImportSendHelper importSendHelper;

    private HandleImportService handleImportService;

    private ImportRedisHelper importRedisHelper;

    private PaasRedisHelper paasRedisHelper;

    private PackageStatusHelp packageStatusHelp;

    public ExcelXlsxSheetContentsHandler(ExcelReadDataDelegated excelReadDataDelegated) {
        this.excelReadDataDelegated = excelReadDataDelegated;
    }

    public ExcelXlsxSheetContentsHandler(ExcelReadDataDelegated excelReadDataDelegated, int startRowIndex, List<FieldAttrEntityForImport> fieldAttrEntityList, ImportFormDataDTO importFormDataDTO, String sheetName, int sheetIndex, ImportSendHelper importSendHelper, HandleImportService handleImportService, ImportRedisHelper importRedisHelper, PaasRedisHelper paasRedisHelper, PackageStatusHelp packageStatusHelp) {
        this.fieldAttrEntityList = fieldAttrEntityList;
        this.importFormDataDTO = importFormDataDTO;
        this.sheetName = sheetName;
        this.startRowIndex = startRowIndex;
        this.sheetIndex = sheetIndex;
        this.excelReadDataDelegated = excelReadDataDelegated;
        this.importSendHelper = importSendHelper;
        this.handleImportService = handleImportService;
        this.importRedisHelper = importRedisHelper;
        this.paasRedisHelper = paasRedisHelper;
        this.packageStatusHelp = packageStatusHelp;
    }

    @Override
    public void startRow(int rowNum) {
        firstCellOfRow = true;
        currentRowNumber = rowNum;
        currentColNumber = -1;
    }

    @Override
    public void endRow(int rowNum) {
        if (isFirstRow) {
            isFirstRow = false;
            if (currentRowNumber == rowIndex) {
                if (rowCells.size() > 0) {
                    String sheetTitle = rowCells.get(0);
                    if (sheetTitle.contains(":")) {
                        try {
                            String titleDep = sheetTitle.substring(sheetTitle.indexOf(":") + 1, sheetTitle.length());
                            startRowIndex = Integer.parseInt(titleDep) - 1;
                        } catch (Exception e) {
                            throw new ExcelTitleCheckException(ImportErrorCodeEnum.API_ERROR_235028.getMsg());
                        }
                    } else {
                        throw new ExcelTitleCheckException(ImportErrorCodeEnum.API_ERROR_235028.getMsg());
                    }
                } else {
                    throw new ExcelTitleCheckException(ImportErrorCodeEnum.API_ERROR_235028.getMsg());
                }
            } else {
                throw new ExcelTitleCheckException(ImportErrorCodeEnum.API_ERROR_235028.getMsg());
            }
        }

        if (currentRowNumber < 1) {
            totalRowNum = totalRows - startRowIndex - 1;
            if (Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode())) {
                Integer maxExcelCustomerImportCount = ImportConstant.MAX_EXCEL_CUSTOMER_IMPORT_COUNT;
                if (importSendHelper.checkIsImportLargeNum(importFormDataDTO.getCorpid())) {
                    maxExcelCustomerImportCount = ImportConstant.MAX_LARGE_NUM_COMPANY_IMPORT_COUNT;
                }
                if (totalRowNum > maxExcelCustomerImportCount) {
                    LOG.error("导入数据量错误！", importFormDataDTO.getCorpid() + "_" + importFormDataDTO.getUserId());
                    throw new ExcelAnalysisException(String.format(I18nMessageUtil.getMessage(I18nStringConstant.IMPORT_NOT_MORE), maxExcelCustomerImportCount));
                }
            } else {
                Integer maxExcelImportCount = ImportConstant.MAX_EXCEL_IMPORT_COUNT;
                if (importSendHelper.checkIsImportLargeNum(importFormDataDTO.getCorpid())) {
                    maxExcelImportCount = ImportConstant.MAX_LARGE_NUM_COMPANY_IMPORT_COUNT;
                }
                if (totalRowNum > maxExcelImportCount) {
                    LOG.error("导入数据量错误！", importFormDataDTO.getCorpid() + "_" + importFormDataDTO.getUserId());
                    throw new ExcelAnalysisException(String.format(I18nMessageUtil.getMessage(I18nStringConstant.IMPORT_NOT_MORE), maxExcelImportCount));
                }
            }
            if (totalRowNum < BasicConstant.ONE) {
                throw new ExcelAnalysisException(String.format(I18nMessageUtil.getMessage(I18nStringConstant.IMPORT_NOT_LESS), BasicConstant.ONE));
            }
            try {
                XbbRefTypeEnum xbbRefTypeEnum = XbbRefTypeEnum.getByCode(importFormDataDTO.getBusinessType());
                Integer oneStatus = packageStatusHelp.getPackageStatus(importFormDataDTO.getCorpid(), ValueAddedTypeEnum.ONE_FORM_DATA_NUM, 1, xbbRefTypeEnum, importFormDataDTO.getFormId());
                Integer allStatus = packageStatusHelp.getPackageStatus(importFormDataDTO.getCorpid(), ValueAddedTypeEnum.TOTAL_FORM_DATA_NUM, 1);

                //TODO 后面还有一次校验.
                if(!Objects.equals(oneStatus, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(oneStatus, PackageStatusEnum.WARNING.getCode())){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100074, I18nStringConstant.SINGLE_TABLE_NUM_LIMIT);
                }

                if(!Objects.equals(allStatus, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(allStatus, PackageStatusEnum.WARNING.getCode())){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100074, I18nStringConstant.TOTAL_TABLE_NUM_LIMIT);
                }
            } catch (XbbException e) {
                throw new ExcelAnalysisException(e.getMsg());
            }


            // 保存初始的粗略分片大小
            falseTotalFragmentation = totalRowNum / ExcelConstant.PER_READ_INSERT_BATCH_COUNT + 1;
        }

        // 获取表头
        if (currentRowNumber <= startRowIndex && currentRowNumber > rowIndex) {
            List<String> titles = new ArrayList<>(rowCells);
            titleLists.add(titles);
        }
        // 处理数据
        if (currentRowNumber > startRowIndex) {
            try {
                // 特殊的空行处理，xml有结构但是没有值
                boolean isBlank = rowCells.stream().allMatch(StringUtil::isEmpty);
                if (isBlank) {
                    totalRowNum--;
                } else {
                    actualTotalRowNum++;
                    if (actualTotalRowNum > totalRowNum) {
                        totalRowNum = actualTotalRowNum;
                    }
                    readExcelDataReturnPojo = excelReadDataDelegated.readExcelData(sheetName, sheetIndex, totalRowNum, currentRowNumber, rowCells, titleLists, fieldAttrEntityList, importFormDataDTO);
                }
            } catch (ExcelTitleCheckException | ExcelAnalysisException e) {
                throw e;
            }
        }
        rowCells.clear();
    }

    @Override
    public void cell(String cellReference, String formattedValue, XSSFComment comment) {
        if (firstCellOfRow) {
            firstCellOfRow = false;
        }
        if (cellReference == null) {
            cellReference = new CellAddress(currentRowNumber, currentColNumber).formatAsString();
        }
        int thisCol = (new CellReference(cellReference)).getCol();
        int missedCols = thisCol - currentColNumber - 1;
        for (int i = 0; i < missedCols; i++) {
            rowCells.add("");
        }
        currentColNumber = thisCol;
        // 过滤表格内的换行
        formattedValue = formattedValue.replaceFirst("\n", "");
        formattedValue = formattedValue.trim();
        rowCells.add(formattedValue);
    }

    @Override
    public void headerFooter(String text, boolean isHeader, String tagName) {

    }

    @Override
    public void endDocument() {
        if (Objects.nonNull(readExcelDataReturnPojo)) {

            String checkRepeatKey = readExcelDataReturnPojo.getCheckRepeatKey();
            List<RowGroupPojo> rowGroupPojoList = readExcelDataReturnPojo.getRowGroupPojoList();
            // 清除当次导入的查重数据
            if (StringUtil.isNotEmpty(checkRepeatKey)) {
                // TODO: 2021/1/29 优先处理客户的，其他模块后续做
                if (Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode())) {
                    String[] split = checkRepeatKey.split("-");
                    String endStr = split[split.length - 1];
                    if (!Objects.equals(endStr, "null")) {
                        List<ErrorExcelDataPojo> errorList = new ArrayList<>();
                        Iterator<RowGroupPojo> iterator = rowGroupPojoList.iterator();
                        while (iterator.hasNext()) {
                            RowGroupPojo next = iterator.next();
                            String groupTagValue = next.getGroupTagValue();
                            Boolean isRepeat = importRedisHelper.checkImportRepeat(checkRepeatKey, groupTagValue);
                            if (isRepeat) {
                                // 有重复数据 扔到错误队列
                                ErrorExcelDataPojo errorExcelDataPojo = new ErrorExcelDataPojo(I18nMessageUtil.getMessage(ErrorMessageConstant.EXCEL_DUPLICATE_OR_OTHER_IMPORT), next);
                                errorList.add(errorExcelDataPojo);
                                iterator.remove();
                            }
                        }
                        if (errorList.size() != 0) {
                            String hashKey = importFormDataDTO.getCorpid() + "_" + importFormDataDTO.getUserId();
                            String formHashKey = hashKey + "_" + importFormDataDTO.getFormId();
                            importRedisHelper.updateImportList(RedisPrefixConstant.IMPORT_ERROR_EXCEL_KEY, formHashKey, errorList, RedisConstant.LONG_DURATION);

                            ImportStatusPojo importStatusPojo = new ImportStatusPojo();
                            importStatusPojo.setSuccessNum(0);
                            importStatusPojo.setErrorNum(errorList.size());
                            importStatusPojo.setUpdateNum(0);
                            importStatusPojo.setNoSignNum(0);
                            if (rowGroupPojoList.size() > 0) {
                                importRedisHelper.updateImportStatus(hashKey, importStatusPojo, 0);
                                paasRedisHelper.setValue(RedisPrefixConstant.IMPORT_START_FLAG_KEY, hashKey, BasicConstant.ONE_STRING, TimeConstant.SECONDS_EIGHT_HOUR);
                            } else {
                                importRedisHelper.updateImportStatus(hashKey, importStatusPojo, 1);
                                paasRedisHelper.setValue(RedisPrefixConstant.IMPORT_START_FLAG_KEY, hashKey, BasicConstant.ONE_STRING, TimeConstant.SECONDS_EIGHT_HOUR);
                            }
                        }
                    }
                }
            }


            // 更新总分片数缓存,如果最后实际分片和粗略计算的不一致，对分片数的缓存进行修正
            int totalFragmentation = readExcelDataReturnPojo.getTotalFragmentation();
            if (!Objects.equals(totalFragmentation, falseTotalFragmentation)) {
                String key = importFormDataDTO.getCorpid() + "_" + importFormDataDTO.getUserId();
                importRedisHelper.decrImportTotalFragmentation(key, (long) (falseTotalFragmentation - totalFragmentation));
            }

            if (Objects.equals(importFormDataDTO.getSaasMark(), SaasMarkEnum.SAAS.getCode())) {
                // saas
                if (Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.QUOTATION.getCode()) || Objects.equals(importFormDataDTO.getBusinessType(), XbbRefTypeEnum.CONTRACT.getCode())) {
                    try {
                        rowGroupPojoList = handleImportService.handleDiscount(rowGroupPojoList, fieldAttrEntityList);
                    } catch (XbbException e) {
                        throw new ExcelAnalysisException(e.getMessage());
                    }
                }
            }
            List<CellTitlePojo> cellTitlePojoList = readExcelDataReturnPojo.getCellTitlePojoList();
            JSONArray fieldJsonArray = readExcelDataReturnPojo.getFieldJsonArray();
            if (Objects.nonNull(rowGroupPojoList) && rowGroupPojoList.size() > 0) {
                // 发送到mq处理
                try {
                    ImportMessageFormDataDTO message = new ImportMessageFormDataDTO();
                    message.setTotalSize(totalRows - startRowIndex - 1);
                    List<ImportMessageFormDataDTO.RowGroupPojo> staticRowGoupPojoList = new ArrayList<>(rowGroupPojoList.size());
                    BeanUtil.copyPropertiesList(rowGroupPojoList, staticRowGoupPojoList, ImportMessageFormDataDTO.RowGroupPojo.class);
                    message.setRowGroupPojoList(staticRowGoupPojoList);
                    int totalRowNum = 0;
                    for (RowGroupPojo groupPojo : rowGroupPojoList) {
                        totalRowNum += groupPojo.getRowValueList().size();
                    }
                    message.setTotalRowNum(totalRowNum);
                    message.setImportFormDataDTO(importFormDataDTO);
                    List<ImportMessageFormDataDTO.CellTitlePojo> staticTitlePojoList = new ArrayList<>(cellTitlePojoList.size());
                    BeanUtil.copyPropertiesList(cellTitlePojoList, staticTitlePojoList, ImportMessageFormDataDTO.CellTitlePojo.class);
                    message.setTitlePojoLis(staticTitlePojoList);
                    message.setJsonArray(fieldJsonArray);
                    message.setCheckRepeatKey(checkRepeatKey);
                    importSendHelper.sendMessage(message);
                } catch (Exception e) {
                    // TODO: 2019/11/21
                    LOG.error("com.xbongbong.paas.util.ExcelXlsxSheetContentsHandler.endDocument rabbitmq send message error", e);
                }

                readExcelDataReturnPojo.getRowGroupPojoList().clear();
            }
        }
    }

    @Override
    public void setTotalRowNum(int totalRowNum) {
        this.totalRows = totalRowNum;
    }

}
